防止PyQt对发生在槽中的异常进行沉默处理

您所在的位置:网站首页 pyqt 退出程序 防止PyQt对发生在槽中的异常进行沉默处理

防止PyQt对发生在槽中的异常进行沉默处理

#防止PyQt对发生在槽中的异常进行沉默处理| 来源: 网络整理| 查看: 265

当在IPython控制台中运行时,覆盖sys.excepthook不起作用,因为IPython在单元格被执行时,会主动再次覆盖它。

这就是为什么jlujans的解决方案见上文在我看来是非常优雅的。

我意识到的是,你可以在装饰器函数中添加一些漂亮的关键字参数,用于定制异常的类型来捕捉,也是为了当槽中发生异常时,发出一个pyqtSignal。. This 例子在PyQt5上运行:

import sys import traceback import types from functools import wraps from PyQt5.QtCore import pyqtSlot, pyqtSignal from PyQt5.QtWidgets import QPushButton, QWidget, QApplication, QMessageBox def pyqtCatchExceptionSlot(*args, catch=Exception, on_exception_emit=None): """This is a decorator for pyqtSlots where an exception in user code is caught, printed and a optional pyqtSignal with signature pyqtSignal(Exception, str) is emitted when that happens. Arguments: *args: any valid types for the pyqtSlot catch: Type of the exception to catch, defaults to any exception on_exception_emit: name of a pyqtSignal to be emitted """ if len(args) == 0 or isinstance(args[0], types.FunctionType): args = [] @pyqtSlot(*args) def slotdecorator(func): @wraps(func) def wrapper(*args, **kwargs): try: func(*args) except catch as e: print(f"In pyqtSlot: {wrapper.__name__}:\n" f"Caught exception: {e.__repr__()}") if on_exception_emit is not None: # args[0] is instance of bound signal pyqt_signal = getattr(args[0], on_exception_emit) pyqt_signal.emit(e, wrapper.__name__) return wrapper return slotdecorator class Test(QPushButton): exceptionOccurred = pyqtSignal(Exception, str) def __init__(self, parent=None): super().__init__(parent) self.setText("hello") self.clicked.connect(self.buttonClicked) self.exceptionOccurred.connect(self.on_exceptionOccurred) @pyqtSlot(Exception, str) def on_exceptionOccurred(self, exception, slot_name): QMessageBox.critical(self, "Uncaught exception in pyqtSlot!", f"In pyqtSlot: {slot_name}:\n" f"Caught exception: {exception.__repr__()}") @pyqtCatchExceptionSlot("bool", on_exception_emit="exceptionOccurred") def buttonClicked(self, checked): print("clicked") raise Exception("wow") class MyApp(QApplication): def notify(self, obj, event): isex = False try: return QApplication.notify(self, obj, event) except Exception: isex = True print("Unexpected Error") print(traceback.format_exception(*sys.exc_info())) return False finally: if isex: self.quit() app = MyApp(sys.argv) t=Test() t.show() # Some boilerplate in case this is run from an IPython shell try: from IPython import get_ipython ipy_inst = get_ipython() if ipy_inst is None: app.exec_() else: ipy_inst.run_line_magic("gui", "qt5") except ImportError: app.exec_()

我发现同样有效(但似乎没有明显或干净的解决方案)的是对sys.excepthook/inside/pqyt事件处理程序进行猴子式的修补,我在下面找到了另一个主题贴:

"""Monkey-patch sys.excepthook /inside/ a PyQt event, e.g. for handling exceptions occuring in pyqtSlots. """ import sys from traceback import format_exception from PyQt5.QtCore import QTimer from PyQt5.QtWidgets import QMessageBox def new_except_hook(etype, evalue, tb): QMessageBox.information( None, "Error", "".join(format_exception(etype, evalue, tb))) def patch_excepthook(): sys.excepthook = new_except_hook TIMER = QTimer() TIMER.setSingleShot(True) TIMER.timeout.connect(patch_excepthook) TIMER.start()


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3